/**
 * 
 */
package smallChanges.statements;

import net.sourceforge.pmd.ast.ASTAllocationExpression;
import net.sourceforge.pmd.ast.ASTArgumentList;
import net.sourceforge.pmd.ast.ASTArguments;
import net.sourceforge.pmd.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.ast.ASTExplicitConstructorInvocation;
import net.sourceforge.pmd.ast.ASTExpression;
import net.sourceforge.pmd.ast.ASTPrimaryExpression;
import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
import net.sourceforge.pmd.ast.ASTPrimarySuffix;
import net.sourceforge.pmd.ast.JavaParserVisitorAdapter;
import net.sourceforge.pmd.ast.Node;
import net.sourceforge.pmd.ast.SimpleJavaNode;
import smallChanges.Tokenization.TokenSet;
import smallChanges.util.SCConstants;

/**
 * @author jspacco
 *
 */
public class MethodCallFinder extends JavaParserVisitorAdapter implements SCConstants
{
    private TokenSet tokenSet;
    
    public MethodCallFinder(TokenSet tokenSet) {
        this.tokenSet=tokenSet;
    }
    
    

    @Override
    public Object visit(ASTExplicitConstructorInvocation node, Object data)
    {
        if (data instanceof Statement) {
            Statement statement=(Statement)data;
            MetaInformationAnnotation mi=new MetaInformationAnnotation(tokenSet, EXPLICIT_CONSTRUCTOR_INVOCATION);
            mi.setCoordinatesFromToken(tokenSet.getAllTokensComprisingNode(node).getFirst());
            statement.addMetaInfo(mi);
        }
        return super.visit(node, data);
    }



    @Override
    public Object visit(ASTPrimaryExpression node, Object data)
    {
        if (data instanceof Statement) {
            Statement statement=(Statement)data;
            // Is this a method call?
            for (int ii=0; ii < node.jjtGetNumChildren(); ii++) {
                Node n=node.jjtGetChild(ii);
                if (n instanceof ASTPrimarySuffix &&
                        n.jjtGetNumChildren()==1 &&
                        (n.jjtGetChild(0) instanceof ASTArguments))
                {
                    // OK, we found a parameter list, so there is 
                    // at least one method call in here!
                    // whatever came right before this is the method invocation
                    // it might be ASTPrimaryPrefix or ASTPrimarySuffix
                    SimpleJavaNode invocationNode=(SimpleJavaNode)node.jjtGetChild(ii-1);
                    if (invocationNode instanceof ASTPrimaryPrefix ||
                            invocationNode instanceof ASTPrimarySuffix)
                    {
                        MetaInformationAnnotation methodName=
                            new MetaInformationAnnotation(tokenSet, METHOD_INVOCATION);
                        methodName.setCoordinatesFromNode(invocationNode);
                        // If we find more than one token, then we've also grabbed
                        // the DOT "." and we need to throw that out
                        while (methodName.getTokensInRange().size()>1) {
                            methodName.shrinkByOnePrecedingToken();
                        }
                        statement.addMetaInfo(methodName);
                    }
                }
            }
        }
        return super.visit(node, data);
    }

    @Override
    public Object visit(ASTArgumentList node, Object data)
    {
        if (data instanceof Statement) {
            Statement statement=(Statement)data;
            if (node.jjtGetNumChildren() > 0) {
                // handle actual parameters, if any
                for (int ii=0; ii<node.jjtGetNumChildren(); ii++) {
                    ASTExpression e=(ASTExpression)node.jjtGetChild(ii);
                    MetaInformationAnnotation actualParam=
                        new MetaInformationAnnotation(tokenSet, ACTUAL_PARAMETER);
                    actualParam.setCoordinatesFromNode(e);
                    statement.addMetaInfo(actualParam);
                }
            }
        }
        return super.visit(node, data);
    }

    @Override
    public Object visit(ASTAllocationExpression node, Object data)
    {
        if (data instanceof Statement) {
            Statement statement=(Statement)data;
            
            if (node.jjtGetNumChildren()==1) {
                // constructor invocation
                ASTClassOrInterfaceType type=(ASTClassOrInterfaceType)node.jjtGetChild(0);
                MetaInformationAnnotation constructorInvocation=
                    new MetaInformationAnnotation(tokenSet, CONSTRUCTOR_INVOCATION);
                constructorInvocation.setCoordinatesFromNode(type);
                statement.addMetaInfo(constructorInvocation);
            } else if (node.jjtGetNumChildren()==2) {
                // array constructor
                SimpleJavaNode type=(SimpleJavaNode)node.jjtGetChild(0);
                SimpleJavaNode dimensions=(SimpleJavaNode)node.jjtGetChild(1);
                MetaInformationAnnotation arrayConstructor=
                    new MetaInformationAnnotation(tokenSet, ARRAY_CONSTRUCTOR_INVOCATION);
                arrayConstructor.setBeginCoordsFromNode(type);
                arrayConstructor.setEndCoordsFromNode(dimensions);
                statement.addMetaInfo(arrayConstructor);
            }
        }
        return super.visit(node, data);
    }
    
    
}
